package com.gemini.main.proxy;

import javassist.util.proxy.MethodHandler;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.This;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * gemini
 * com.gemini.main.proxy.InvokeHandler
 *
 * @author zhanghailin
 */
public class InvokeHandler implements InvocationHandler, MethodHandler, MethodInterceptor {

    private Object doInvoke(Object proxy, Method method, Object[] args) {
        if (Object.class == method.getDeclaringClass()) {
            String name = method.getName();
            if ("equals".equals(name)) {
                return proxy == args[0];
            } else if ("hashCode".equals(name)) {
                return System.identityHashCode(proxy);
            } else if ("toString".equals(name)) {
                return proxy.getClass().getName() + "@" +
                        Integer.toHexString(System.identityHashCode(proxy)) +
                        ", with InvokeHandler " + this;
            } else {
                throw new IllegalStateException(String.valueOf(method));
            }
        }
        //TODO RPC调用
        return null;
    }

    /**
     * jdk invoke
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return doInvoke(proxy, method, args);
    }

    /**
     * byteBuddy invoke
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @RuntimeType
    public Object byteBuddyInvoke(@This Object proxy, @Origin Method method, @AllArguments @RuntimeType Object[] args) throws Throwable {
        return doInvoke(proxy, method, args);
    }

    /**
     *  javassist invoke
     * @param self
     * @param thisMethod
     * @param proceed
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        return doInvoke(self, thisMethod, args);
    }

    /**
     * cglib
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return doInvoke(o, method, objects);
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = new CompletableFuture<>();
        Thread messageThread = new Thread(() -> {
           future.complete("123");
        });
        messageThread.start();
        String message = future.get();
        System.out.println(message);
    }
}
